/**
  * DispatcherFilter.java
 *
 * Copyright (C) 2009,  Tomislav Milkovic
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package ws4is.engine;


import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ws4is.engine.actions.AFilterAction;
import ws4is.engine.actions.AServletAction;
import ws4is.engine.enums.ActionScope;
import ws4is.engine.enums.HTTPRequestType;

/*
 * Main class for implementing servlet filters 
 */
public abstract class ADispatcherFilter  implements Filter, IDispatcher{

	protected final Logger loger = LoggerFactory.getLogger(this.getClass());
	protected ConfigLoader engine;
	protected Map<String,AFilterAction> filterActions = new HashMap<String,AFilterAction>();
	
	FilterConfig fc = null;
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		this.fc = filterConfig;
		engine = new ConfigLoader(filterConfig.getServletContext(),this);
	}
	
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response,	FilterChain chain) throws IOException, ServletException {		 			
		try{
			engine.processAction(HTTPRequestType.FILTER, (HttpServletRequest)request, (HttpServletResponse)response, chain);
		}catch(Exception e){
			engine.printMessage((HttpServletResponse)response, e,null);
			loger.error("ERROR ON FILTER",e);
		}
   }
	
	@Override
	public void destroy() {
		this.fc = null;	
		engine.releaseResources();
	}


	
	@Override
	public void callMethod(final String actionClass ,ConfigObject config, HTTPRequestType type,HttpServletRequest request, HttpServletResponse response,FilterChain chain)	throws Exception, IOException {

		Exception ex = null;
		try {
			if (actionClass == null) {
				if (actionNotFoundReponse(request,response)){
					chain.doFilter(request, response);
				}
				return;
			}	
			
			
			AFilterAction actionObject = null;
			ActionScope as = config.getScope();
			switch(as) {
			   //global in context of this filter; not available outside filter
				case GLOBAL : {
					actionObject = filterActions.get(actionClass);
					if (actionObject==null){
						Constructor<AFilterAction> con = config.getActionConstructor();
						actionObject = con.newInstance();	
						filterActions.put(actionClass, actionObject );
					}				
					break;
				  }
				//on each request new action instantiation is performed
				case REQUEST :{
					Constructor<AFilterAction> con = config.getActionConstructor();
					actionObject = con.newInstance();						
					break;
				  }
				//client session is keeps filter action; available in other actions
				case SESSION : {
					HttpSession ses = request.getSession();
					Map<String,AFilterAction>  sessionFilterActions = null;
					sessionFilterActions = (Map<String, AFilterAction>) ses.getAttribute(getClass().getCanonicalName());
					if (sessionFilterActions==null){
						sessionFilterActions = new HashMap<String, AFilterAction>();
						ses.setAttribute(getClass().getCanonicalName(),sessionFilterActions);
					} else 	actionObject = sessionFilterActions.get(actionClass);
					if (actionObject==null){
						Constructor<AFilterAction> con = config.getActionConstructor();
						actionObject = con.newInstance();	
						sessionFilterActions.put(actionClass, actionObject );
					}	
					break;
				  }
			}
			
	
			actionObject.execute(config, type, request, response, chain);
			
		} catch (Exception e) {
			ex = e;
			//TODO log error executing action
			//printMessage(response ,e.getMessage());
			throw e;
		} finally {
			postAction(type, actionClass, ex);
		}
		
	}


	protected boolean actionNotFoundReponse(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		return true;
	}
	
}
